import tkinter as tk
from tkinter import filedialog, Toplevel
from PIL import Image, ImageTk
import cv2
from doc_scanner import DocScanner
import numpy as np


class DocScannerApp:
    def __init__(self):

        self.doc_scanner = DocScanner()

        self.corners = None
        self.dragging_idx = -1
        self.img = None
        self.cropped_img = None

        # 添加图像尺寸属性
        self.img_width = 600
        self.img_height = 400

        self.root = tk.Tk()

        self.canvas = tk.Canvas(self.root, width=600, height=400)
        self.canvas.pack()

        self.canvas.bind("<ButtonPress-1>", self.mouse_callback)
        self.canvas.bind("<ButtonRelease-1>", self.mouse_callback)
        self.canvas.bind("<B1-Motion>", self.mouse_callback)

        self.canvas.bind("<Motion>", self.mouse_move_callback)

        self.btn_select = tk.Button(self.root, text="Select Image", command=self.select_image)
        self.btn_select.pack(side=tk.LEFT)

        self.btn_confirm = tk.Button(self.root, text="Confirm", command=self.confirm_selection, state=tk.DISABLED)
        self.btn_confirm.pack(side=tk.LEFT)

        self.btn_reset = tk.Button(self.root, text="Reset", command=self.reset_selection, state=tk.DISABLED)
        self.btn_reset.pack(side=tk.LEFT)

        self.show_mouse_move = tk.BooleanVar(value=True)

        chk_show_mouse_move = tk.Checkbutton(self.root, text="Show Mouse Move", variable=self.show_mouse_move)
        chk_show_mouse_move.pack(side=tk.LEFT)

        self.selection_complete = False

        self.info = tk.Text(self.root, height=10, width=50)
        self.info.pack(side=tk.BOTTOM)

    def select_image(self):
        file_path = filedialog.askopenfilename()
        self.img, self.corners = self.doc_scanner.load_image(file_path)

        # 更新窗口和画布的尺寸
        self.img_height, self.img_width = self.img.shape[:2]
        self.root.geometry(f"{self.img_width}x{self.img_height}")
        self.canvas.config(width=self.img_width, height=self.img_height)

        if self.corners is None:
            self.reset_selection()
            self.canvas.bind("<Button-1>", self.select_corner)
            self.canvas.bind("<Motion>", self.mouse_move_callback)
        else:
            self.selection_complete = True
            self.canvas.unbind("<Button-1>")
            self.canvas.unbind("<Motion>")
            self.btn_confirm.config(state=tk.NORMAL)
            self.btn_reset.config(state=tk.NORMAL)

        self.redraw()
        self.info.insert(tk.END, f"Image selected: {file_path}\n")
        self.canvas.bind("<Motion>", self.mouse_move_callback)
        self.insert_info(f"Image selected: {file_path}\n")

    def select_corner(self, event):
        try:
            x, y = event.x, event.y
            self.insert_info(f"选择的角点: ({x}, {y})\n")

            if self.corners is None:
                self.corners = []

            if len(self.corners) < 4:
                self.corners.append([x, y])
                self.redraw()

                # 添加标签显示角点坐标
                self.canvas.create_text(x, y, text=f"({x},{y})", tags="corner")

            if len(self.corners) == 4:
                self.selection_complete = True
                self.canvas.unbind("<Button-1>")
                self.canvas.unbind("<Motion>")
                self.btn_confirm.config(state=tk.NORMAL)
                self.btn_reset.config(state=tk.NORMAL)
            self.insert_info(f"当前角点: {self.corners}\n")
        except Exception as e:
            self.insert_info(f"出现错误: {str(e)}\n")

    def mouse_move_callback(self, event):
        x, y = event.x, event.y
        self.insert_info(f"Mouse position: ({x}, {y})\n")
        if self.show_mouse_move.get():
            self.root.title(f"Mouse Position: ({x}, {y})")

    def mouse_callback(self, event):
        x, y = event.x, event.y
        self.insert_info(f"Mouse position: ({x}, {y})\n")
        if event.type == tk.EventType.ButtonPress:
            for idx, corner in enumerate(self.corners):
                if np.linalg.norm(corner - np.array([x, y])) < 10:
                    self.dragging_idx = idx
                    break

            # 添加临时标签显示鼠标按下的位置
            self.canvas.create_text(x, y, text=f"按下位置({x},{y})", tags="temp")

        elif event.type == tk.EventType.ButtonRelease:
            self.dragging_idx = -1

            # 添加临时标签显示鼠标释放的位置
            self.canvas.create_text(x, y, text=f"释放位置({x},{y})", tags="temp")

        elif event.type == tk.EventType.Motion:
            if self.dragging_idx != -1:
                self.corners[self.dragging_idx] = np.array([x, y])
                self.redraw()


    def redraw(self):
        # 清除所有临时标签
        self.canvas.delete("temp")

        if self.corners is not None:
            img_copy = self.img.copy()
            for idx, corner in enumerate(self.corners):
                cv2.circle(img_copy, tuple(corner.astype(int)), 5, (0, 255, 0), -1)
            cv2.polylines(img_copy, [np.int32(self.corners)], True, (0, 255, 0), 2)
            img_tk = self.cv2image_to_tkinter_image(img_copy)
            self.canvas.create_image(0, 0, anchor=tk.NW, image=img_tk)
            self.canvas.image = img_tk

            if self.selection_complete:
                # 重新绑定事件，限制鼠标事件的触发范围在所选择的区域内
                self.canvas.bind("<ButtonPress-1>", self.mouse_callback_in_selection)
                self.canvas.bind("<ButtonRelease-1>", self.mouse_callback_in_selection)
                self.canvas.bind("<B1-Motion>", self.mouse_callback_in_selection)
                self.canvas.bind("<Motion>", self.mouse_move_callback)



    def mouse_callback_in_selection(self, event):
        x, y = event.x, event.y
        if event.type == tk.EventType.ButtonPress:
            for idx, corner in enumerate(self.corners):
                if np.linalg.norm(corner - np.array([x, y])) < 10:
                    self.dragging_idx = idx
                    break
        elif event.type == tk.EventType.ButtonRelease:
            self.dragging_idx = -1
        elif event.type == tk.EventType.Motion:
            if self.dragging_idx != -1:
                self.corners[self.dragging_idx] = np.array([x, y])
                self.redraw()

    def cv2image_to_tkinter_image(self, cv2_image):
        cv2_image_rgb = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
        pil_image = Image.fromarray(cv2_image_rgb)
        return ImageTk.PhotoImage(pil_image)

    def confirm_selection(self):
        try:
            self.insert_info("确认选择，开始裁剪...\n")
            self.canvas.unbind("<Button-1>")
            self.canvas.unbind("<Motion>")
            self.btn_confirm.config(state=tk.DISABLED)
            self.btn_reset.config(state=tk.DISABLED)
            self.btn_select.config(state=tk.DISABLED)

            # 裁剪图像并显示在新窗口中
            self.cropped_img = self.doc_scanner.transform(self.img, self.corners)

            # 创建新窗口
            top_level = Toplevel(self.root)
            top_level.title("裁剪后的图像")

            # 创建画布并显示裁剪后的图像
            cropped_canvas = tk.Canvas(top_level, width=self.cropped_img.shape[1], height=self.cropped_img.shape[0])
            cropped_canvas.pack()
            img_tk = self.cv2image_to_tkinter_image(self.cropped_img)
            cropped_canvas.create_image(0, 0, anchor=tk.NW, image=img_tk)
            cropped_canvas.image = img_tk

            # 添加功能操作按钮
            btn_save = tk.Button(top_level, text="保存", command=self.save_image)
            btn_save.pack(side=tk.LEFT)
            btn_reset = tk.Button(top_level, text="重置", command=self.reset_selection)
            btn_reset.pack(side=tk.LEFT)
        except Exception as e:
            self.insert_info(f"出现错误: {str(e)}\n")

    def insert_info(self, msg):
        self.info.insert(tk.END, msg)
        self.info.see(tk.END)

    def reset_selection(self):
        self.insert_info("Selection reset\n")
        self.corners = None
        self.selection_complete = False
        self.btn_confirm.config(state=tk.DISABLED)
        self.btn_reset.config(state=tk.DISABLED)
        self.btn_select.config(state=tk.NORMAL)
        if self.img is not None:  # 添加判断以避免在重新选择图像时出错
            self.redraw()

        self.canvas.bind("<Button-1>", self.select_corner)
        self.canvas.bind("<Motion>", self.mouse_move_callback)

    def save_image(self):
        file_path = filedialog.asksaveasfilename(defaultextension=".jpg")
        cv2.imwrite(file_path, self.cropped_img)
        self.insert_info(f"Image saved to: {file_path}\n")

    def run(self):
        self.root.mainloop()


if __name__ == "__main__":
    app = DocScannerApp()
    app.run()

import os
print(os.getcwd())

